package org.fnzn.filter;

import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.fnzn.bean.LogInfo;
import org.fnzn.bean.vo.PermissionInfo;
import org.fnzn.bean.vo.User;
import org.fnzn.util.ClientUtil;
import org.fnzn.util.DBLog;
import org.fnzn.web.LogService;
import org.fnzn.web.UserService;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Created by ace on 2017/7/8.
 */
//@WebFilter(filterName="resourceAccessFilter",urlPatterns="/*")
@Component
@Slf4j
public class ResourceAccessFilter implements Filter {
	/*@Autowired
	private LoginService loginService;*/
	@Autowired
	private UserService userService;
    @Autowired
    private LogService logService;
    @Value("${gate.ignore.startWith1}")
    private String startWith1;
    @Value("${gate.ignore.startWith2}")
    private String startWith2;
    @Value("${gate.ignore.contain}")
    private String contain;

    /**
     * 读取权限
     * @param request
     * @param username
     * @return
     */
    @SuppressWarnings("unchecked")
	private List<PermissionInfo> getPermissionInfos(HttpServletRequest request, String username) {
        List<PermissionInfo> permissionInfos;
        if (request.getSession().getAttribute("permission") == null) {
            permissionInfos = userService.getPermissionByUsername(username);
            request.getSession().setAttribute("permission", permissionInfos);
        } else {
            permissionInfos = (List<PermissionInfo>) request.getSession().getAttribute("permission");
        }
        return permissionInfos;
    }

    /**
     * 权限校验
     * @param requestUri
     * @param method
     */
    private boolean checkAllow(final String requestUri, final String method , HttpServletRequest request, String username) {
        log.debug("uri：" + requestUri + "----method：" + method);
        List<PermissionInfo> permissionInfos = getPermissionInfos(request, username) ;
        Collection<PermissionInfo> result =
                Collections2.filter(permissionInfos, new Predicate<PermissionInfo>() {
                    @Override
                    public boolean apply(PermissionInfo permissionInfo) {
                        String url = permissionInfo.getUri();
                        String uri = url.replaceAll("\\{\\*\\}", "[a-zA-Z\\\\d]+");
                        String regEx = "^" + uri + "$";
                        return (Pattern.compile(regEx).matcher(requestUri).find() || requestUri.startsWith(url + "/"))
                                && method.equals(permissionInfo.getMethod());
                    }
                });
        if (result.size() <= 0) {
            return false;
        } else{
            PermissionInfo[] pms =  result.toArray(new PermissionInfo[]{});
            PermissionInfo pm = pms[0];
            if(!method.equals("GET")){
                setCurrentUserInfoAndLog(request, username, pm);
            }
            return true;
        }
    }
    /**
     * 设置用户操作日志
     * @param request
     * @param username 用户名
     * @param pm 权限
     */
    private void setCurrentUserInfoAndLog(HttpServletRequest request, String username, PermissionInfo pm) {
        User user = (User) request.getSession().getAttribute("user");
        String host =  ClientUtil.getClientIp(request);
        request.setAttribute("userId", user.getUser_id());
        request.setAttribute("userName", user.getUserName());
        request.setAttribute("userHost", ClientUtil.getClientIp(request));
        LogInfo logInfo = new LogInfo(pm.getMenu(),pm.getName(),pm.getUri(),new Date(),
        		user.getUser_id(),user.getUserName(),host,user.getCorpCD(),user.getOrgCD());
        DBLog.getInstance().setLogService(logService).offerQueue(logInfo);
    }

    /**
     * 是否包含某种特征
     * @param requestUri
     * @return
     */
    private boolean isContains(String requestUri) {
        boolean flag = false;
        for (String s : contain.split(",")) {
            if (requestUri.contains(s))
                return true;
        }
        return flag;
    }

    /**
     * URI是否以什么打头
     * @param requestUri
     * @return
     */
    private boolean isStartWith1(String requestUri) {
        boolean flag = false;
        for (String s : startWith1.split(",")) {
            if (requestUri.startsWith(s))
                return true;
        }
        return flag;
    }
    /**
     * URI是否以什么打头
     * @param requestUri
     * @return
     */
    private boolean isStartWith2(String requestUri) {
        boolean flag = false;
        for (String s : startWith2.split(",")) {
            if (requestUri.startsWith(s))
                return true;
        }
        return flag;
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        response.setHeader("Access-Control-Allow-Origin",request.getHeader("Origin"));  
        response.setHeader("Access-Control-Allow-Credentials", "true");  
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, x-access-token,serialize");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        final String method = request.getMethod();
        final String requestUri = request.getRequestURI();
        User user=(User) request.getSession().getAttribute("user");
        // 不进行拦截的地址
        if (isStartWith1(requestUri) || isContains(requestUri)||requestUri.equals("/")) {
            filterChain.doFilter(request, response);
            return;
        }else if(user==null&&!method.equalsIgnoreCase("OPTIONS")) {      	
        	response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
            return;
        }else if(isStartWith2(requestUri) || isContains(requestUri)) {//认证后公共访问的地址
        	 filterChain.doFilter(request, response);
             return;
        }else{
            try { 
                if (!checkAllow(requestUri, method, request, user.getUser_id())) {//校验是否有该接口访问权限
                	if (request.getHeader("x-requested-with") != null
            				&& request.getHeader("x-requested-with").equalsIgnoreCase(
            						"XMLHttpRequest")) {
                		response.sendError(HttpServletResponse.SC_FORBIDDEN, "Unauthorized");
                		return ;
                	}
                }
            }catch (Exception e){
               // filterChain.doFilter(request, response);
            }
        }
        filterChain.doFilter(request, response);
    }
    @Override
    public void destroy() {

    }
}
